<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/6/19
 * Time: 17:47
 */
class Ws
{
    const HOST = '0.0.0.0';
    const PORT = 8811;
    const CHAT_PORT = 8812;
    public $ws = null;
    public function __construct()
    {
        //赛事直播
        $this->ws = new swoole_websocket_server(self::HOST, self::PORT);
        //聊天室
        $this->ws->listen(self::HOST, self::CHAT_PORT, SWOOLE_SOCK_TCP);

        $this->ws->set([
            'enable_static_handler' => true,
            'document_root' => '/data/wwwroot/swoole/thinkphp/public/static',
            'worker_num' => 4,
            'task_worker_num' => 4
        ]);

        $this->ws->on('start', [$this, 'onStart']);
        $this->ws->on('workerStart', [$this, 'onWorkerStart']);
        $this->ws->on('request', [$this, 'onRequest']);
        $this->ws->on('open', [$this, 'onOpen']);
        $this->ws->on('message', [$this, 'onMessage']);
        $this->ws->on('task', [$this, 'onTask']);
        $this->ws->on('finish', [$this, 'onFinish']);
        $this->ws->on('close', [$this, 'onClose']);

        $this->ws->start();
    }

    /**
     * @todo 为进程设置名称
     * @param $server
     */
    public function onStart($server)
    {
        swoole_set_process_name('live_master');
    }
    /**
     * @todo 监听workerstart
     * @param $server
     * @param $worker_id
     */
    public function onWorkerStart($server, $worker_id)
    {
        // 定义应用目录
        define('APP_PATH', __DIR__ . '/../application/');
        // 1. 加载基础文件
        //require __DIR__ . '/../thinkphp/base.php';
        require __DIR__ . '/../thinkphp/start.php';
    }

    /**
     * @todo 监听request
     * @param $request
     * @param $reponse
     */
    public function onRequest($request, $reponse)
    {
        //去掉多余请求favicon.ico
        if($request->server['request_uri'] == '/favicon.ico'){
            $reponse->status(404);
            $reponse->end();
            return;
        }
        $_SERVER = [];
        if(isset($request->server)){
            foreach($request->server as $k=>$v){
                $_SERVER[strtoupper($k)] = $v;
            }
        }

        if(isset($request->header)){
            foreach($request->header as $k=>$v){
                $_SERVER[strtoupper($k)] = $v;
            }
        }
        $_FILES = [];
        if(isset($request->files)){
            foreach($request->files as $k=>$v){
                $_FILES[$k] = $v;
            }
        }
        $_GET = [];
        if(isset($request->get)){
            foreach($request->get as $k=>$v){
                $_GET[$k] = $v;
            }
        }
        $_POST = [];
        if(isset($request->post)){
            foreach($request->post as $k=>$v){
                $_POST[$k] = $v;
            }
        }
        //写入访问日志
        $this->writeLog();

        $_POST['http_server'] = $this->ws;

        ob_start();
        // 执行应用并响应
        try{
            think\Container::get('app', [APP_PATH])
                ->run()
                ->send();
        }catch (\Exception $e){
            //todo
        }
        $content = ob_get_contents();
        ob_end_clean();

        $reponse->end($content);
    }

    /**
     * 监听task事件
     */
    public function onTask($serv, $task_id, $work_id, $data)
    {
        //分发task任务机制，让不同任务，走不同的逻辑
        $obj = new app\common\lib\task\Task;
        $method = $data['method'];
        $flag = false;
        
        if(method_exists($obj , $method)){
            $flag = $obj->$method($data['data'], $serv);
        }

        return $flag;
    }

    /**
     * 监听任务完成事件
     * @param $data 注意，这里的data是onTask 返回的内容
     */
    public function onFinish($serv, $task_id, $data)
    {
        echo "taskId:{$task_id}" . PHP_EOL;
        echo "finish-data-success:{$data}--" .date('Y-m-d H:i:s') . PHP_EOL;
    }

    /**
     * 监听连接事件
     * @param $ws
     * @param $request
     */
    public function onOpen($ws, $request)
    {
        //当有client连接时，把fd存入有序redis
        //\app\common\lib\redis\Predis::getInstance()->sAdd(config('redis.live_game_key'), $request->fd);

        echo "clinet_{$request->fd} 连接成功!" . PHP_EOL;
    }

    /**
     * 监听消息事件
     * @param $ws
     * @param $frame
     */
    public function onMessage($ws, $frame)
    {
        //echo "client:{$frame->fd}-push-message:{$frame->data}" . PHP_EOL;
        $ws->push($frame->fd, "server-push-time:".date("Y-m-d H:i:s"));
    }

    /**
     *  监听关闭事件
     * @param $ws
     * @param $fd
     */
    public function onClose($ws, $fd)
    {
        //当有client关闭连接时，把fd从有序redis删除
        //\app\common\lib\redis\Predis::getInstance()->sRem(config('redis.live_game_key'), $fd);
        echo "client {$fd} closed" . PHP_EOL;
    }

    public function writeLog()
    {
        $data = array_merge(['data'=> date("Ymd H:i:s")], $_GET, $_POST, $_SERVER);
        $logs = "";
        foreach($data as $k=>$v){
            $logs .= $k . ":" . $v . " ";
        }
        $file = APP_PATH. '../runtime/log/'.  date('Ym'). '/'. date('d') . '_access.log';

        swoole_async_writefile($file, $logs . PHP_EOL, function($filename){
            //todo
        }, FILE_APPEND);
    }

}

new Ws();
//20台机器    agent->spark(计算)  -> 数据库  elasticsearch   hadoop

//sigterm  sigusr1 (进程)  sigusr2(task)